#include "EControllerQtTree.h"
#include "DefineCommon.h"
#include "EItem.h"
#include "EItemManager.h"
#include "EString.h"
#include "qmap.h"
#include "qtreewidget.h"
#include <ECommandManager.h>
#include <cstdint>



EControllerQtTree::EControllerQtTree()
{
    this->addCmdSenderList(this->getTag());
}

EControllerQtTree::~EControllerQtTree()
{
}

void EControllerQtTree::setTreeWidget(QTreeWidget* w)
{
    this->m_treeWidget = w;

    QObject::connect(this->m_treeWidget, 
                     SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
                     this,
                     SLOT(slotCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))
                     );
}
    
void EControllerQtTree::refresh()
{
    this->m_treeWidget->clear();
    this->m_mapTag2TreeItem.clear();
    this->m_mapTag2EItem.clear();
    this->travelEItem(this->m_rootEItem);
}

bool EControllerQtTree::handleEItem(EItemPtr item, int depth, EItemPtr parentItem)
{
    // ELOG_DEBUG("Name=%s,Depth=%d", item->getName().data(), depth);
    // if item has related tree item
    if(this->m_mapTag2TreeItem.find(item->getTag()) != this->m_mapTag2TreeItem.end())
    {
        EControllerTreeItem* treeItem = this->m_mapTag2TreeItem[item->getTag()];
        this->synTreeItemAndEItem(item, treeItem);
        return true;
    }
    
    //new a Tree Item
    EControllerTreeItem* treeItem = new EControllerTreeItem;
    treeItem->m_tag = item->getTag();
    this->synTreeItemAndEItem(item, treeItem);

    //set to map struct
    this->m_mapTag2TreeItem[item->getTag()] = treeItem;
    this->m_mapTag2EItem[item->getTag()] = item;

    //link Tree Item
    if(depth == 0)
    {
        this->m_treeWidget->addTopLevelItem(treeItem);
    }
    else
    {
        this->m_mapTag2TreeItem[parentItem->getTag()]->addChild(treeItem);
    }

    return true;
}

EItemPtr EControllerQtTree::getSelectedItem()
{
    if(this->m_selectedEItem == nullptr)
    {
        this->m_selectedEItem = this->m_rootEItem;
    }

    return this->m_selectedEItem;

}

void EControllerQtTree::setSelectedItem(EItemPtr item)
{
    this->m_selectedEItem=item;
}

void EControllerQtTree::addItem(long tagTypeItem)
{
    //get parent and check valid
    EItemPtr parent = this->getSelectedItem();
    
    if(parent == nullptr)
    {
        ELOG_ERROR("parent==nullptr");
        return;
    }

    //find typeItem and call construction function
    //then call handleEItem function
    EItemPtr typeItem = EItemManager::instance()->getItemByTag(
            EItemManager::instance()->getItemTypeRoot()
            , tagTypeItem);

    if(typeItem != nullptr)
    {
        EString funName = typeItem->getName() + "_Fun_factory";
        EItemMetaFunctionPtr fun = typeItem->getOrCreatMeta()->getFunction(funName);
        if(fun != nullptr)
        {
            ELOG_DEBUG("funName=%s", fun->getName().data());
            EVariant result;
            fun->call(&result);
            EItem* newItemRawPtr = (EItem*)result.to_intptr_t();
            EItemPtr child(newItemRawPtr);
            parent->addChild(child);
            this->handleEItem(child, -1, parent);

            //push the additem command
            ECommandPtr newCmd = NewSmartPtr(ECommand)();
            newCmd->setSender( (intptr_t)this );
            newCmd->setName("c:addItem");
            newCmd->getOrCreatMeta()->addProperty("tagItem", child->getTag());
            ECommandManager::instance()->pushECommand(newCmd);
        }
    }

    //try to expand the parent item
    QTreeWidgetItem* treeItem = this->getTreeItemByEItemPtr(parent);
    if(treeItem != NULL)
    {
        treeItem->setExpanded(true);
    }


}

void EControllerQtTree::deleteItem(EItemPtr item)
{

}

void EControllerQtTree::deleteItem(long tag)
{
    QMap<long, EControllerTreeItem*>::iterator it = this->m_mapTag2TreeItem.find(tag);
    QMap<long, EItemPtr>::iterator itItem = this->m_mapTag2EItem.find(tag);
    if(it != this->m_mapTag2TreeItem.end())
    {
        EControllerTreeItem* treeItem = this->m_mapTag2TreeItem[tag];
        EItemPtr item = this->m_mapTag2EItem[tag];

        EControllerTreeItem* treeParent = (EControllerTreeItem*)treeItem->parent();
        treeParent->removeChild(treeItem);

        EItemPtr itemParent = this->m_mapTag2EItem[treeParent->m_tag];
        itemParent->removeChild(item.get());

        this->m_mapTag2EItem.erase(itItem);
        this->m_mapTag2TreeItem.erase(it);
    }
}

void EControllerQtTree::copyItem(long tag)
{
    QMap<long, EControllerTreeItem*>::iterator it = this->m_mapTag2TreeItem.find(tag);
    QMap<long, EItemPtr>::iterator itItem = this->m_mapTag2EItem.find(tag);
    if(it != this->m_mapTag2TreeItem.end())
    {
        EItemPtr item = this->m_mapTag2EItem[tag];
        EString className = item->getOrCreatMeta()->getClassName();
        
        //find typeItem to construct new EItem;
        EItemPtr typeItem = EItemManager::instance()->getItemByName(
                EItemManager::instance()->getItemTypeRoot()
                , className);
        //call the _Fun_factory
        EItemPtr newItemPtr;
        if(typeItem != nullptr)
        {
            EString funName = typeItem->getName() + "_Fun_factory";
            EItemMetaFunctionPtr fun = typeItem->getOrCreatMeta()->getFunction(funName);
            if(fun != nullptr)
            {
                EVariant result;
                fun->call(&result);
                EItem* newItemRawPtr = (EItem*)result.to_intptr_t();
                newItemPtr = EItemPtr(newItemRawPtr);
            }
        }

        //get parent EItem and call addChild
        //The reason that get parent EItem from ui's tree item not from EItem::getParent
        //is: EItem's parent may not be more than one, bu ui's tree item is only one
        EControllerTreeItem* treeItem = this->m_mapTag2TreeItem[tag];

        EControllerTreeItem* treeParent = (EControllerTreeItem*)treeItem->parent();
        if(treeParent != NULL && newItemPtr != nullptr)
        {
            EItemPtr parentItem = this->m_mapTag2EItem[treeParent->m_tag];
            parentItem->addChild(newItemPtr);
            
            this->handleEItem(newItemPtr, -1, parentItem);
        }
    }
}

void EControllerQtTree::selectItem(EItemPtr item)
{
    ECommandPtr newCmd = NewSmartPtr(ECommand)();
    newCmd->setSender( this->getTag() );
    newCmd->setSenderName("WidgetTree.EControllerQtTree");
    newCmd->setName("c:selectItem");
    newCmd->addChild(item);
    newCmd->setIfEnableUndo(false);
    ECommandManager::instance()->pushECommand(newCmd);
}

EItemPtr EControllerQtTree::getEItemByTreeItemPtr(QTreeWidgetItem* treeItem)
{
    EItemPtr result = nullptr;
    EControllerTreeItem* tempItem = dynamic_cast<EControllerTreeItem*>(treeItem);
    if(tempItem != NULL 
            && this->m_mapTag2EItem.find(tempItem->m_tag) != this->m_mapTag2EItem.end())
    {
        result = this->m_mapTag2EItem[tempItem->m_tag];
    }
    return result;

}

QTreeWidgetItem* EControllerQtTree::getTreeItemByEItemPtr(const EItemPtr& itemPtr)
{
    QTreeWidgetItem* result = NULL;
    long tag = itemPtr->getTag();
    if(this->m_mapTag2TreeItem.find(tag) != this->m_mapTag2TreeItem.end())
    {
       result = this->m_mapTag2TreeItem[tag]; 
    }

    return result;

}

void EControllerQtTree::slotCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous)
{
    this->m_selectedEItem = this->getEItemByTreeItemPtr(current);
    this->selectItem(this->m_selectedEItem);
}

// EControllerTreeItem* EControllerQtTree::newTreeItemByEItemPtr(const EItemPtr& itemPtr)
// {
    // EControllerTreeItem* treeItem = new EControllerTreeItem;

    // treeItem->m_tag = itemPtr->getTag();

    // return treeItem;
// }

void EControllerQtTree::synTreeItemAndEItem(const EItemPtr& itemPtr, EControllerTreeItem* treeItem)
{
    if(itemPtr->getName().isEmpty())
    {
        EString className = itemPtr->getOrCreatMeta()->getClassName();
        EString name = className
                      + "_" 
                      + EString::number(this->checkItemTypeCount(className));
        itemPtr->setName(name.data());
        treeItem->setText(0, name.data());
    }
    else 
    {
        EString name = itemPtr->getName();
        treeItem->setText(0, name.data());
    }
}

int EControllerQtTree::checkItemTypeCount(const EString& className)
{
    int result = 0;
    QMap<long, EItemPtr>::iterator it = this->m_mapTag2EItem.begin();
    for(; it != this->m_mapTag2EItem.end(); it++)
    {
        EItemPtr item = it.value();
        if( className == item->getOrCreatMeta()->getClassName())
        {
            result++;
        }
    }
    return result;
}

void EControllerQtTree::handleCommand(const ECommandPtr& command)
{
    // ELOG_DEBUG("cmd.name=%s", command->getName().data());
    if(command->getName() == "c:addItem" 
            && command->getState() == ECommand::STATE::UNDO
            && ifCmdSenderValid(command->getSender()))
    {
        long tagItem = command->getOrCreatMeta()->getProperty("tagItem")->value.to_intptr_t();
    }
    else if(command->getName() == "c:propertyChanged" 
            && command->getState() == ECommand::STATE::UNDO
            && ifCmdSenderValid(command->getSender()) )
    {
    }
    
}
